This function imports and exports data in JavaScript Object Notation (JSON) Data Interchange Format1IETF RFC 7159 - The JavaScript Object Notation (JSON) Data Interchange Format - is a widely supported, text based data interchange format for the portable representation of structured data; any application which conforms to the standard may exchange data with any other..
If specified, X must be a numeric scalar with the value 0 (import JSON) or 1 (export JSON). If X is not specified and Y is a character array, X is assumed to be 0 (import); otherwise it is assumed to be 1 (export).
Other options for ⎕JSON are Format , Compact and Null which are specified using the Variant operator ⍠.
The Null variant specifies the APL representation of a JSON null value. It may be either ⊂'null' (the default) or ⎕NULL.
Y is a character vector or matrix in JSON format. There is an implied newline character between each row of a matrix.
The content of the result R depends upon the Format variant which may be 'D' (the default) or 'M'.
If Format is 'D' (which stands for "data") the JSON described by Y is converted to APL object(s) and R is an array or a namespace containing arrays and sub-namespaces.
If Format is 'M' (which stands for "matrix") the result R is a matrix whose columns contain the following:
[;1] | depth |
[;2] | name (for JSON object members) |
[;3] | value |
[;4] | JSON type (integer: see below) |
JSON types are as follows:
Type | Description |
---|---|
1 | Object |
2 | Array |
3 | Numeric |
4 | String |
5 | Null |
6 | Boolean (true / false) |
7 | JavaScript Object (export only) |
Table 24: JSON data types
The JSON standard says that members of a JSON object should have unique names and that different implementations behave differently when there are duplicates. Dyalog handles duplicate names as follows:
⍴JSON 18 19 JSON { "a": { "b": [ "string 1", "string 2" ], "c": true, "d": { "e": false, "f⍺": [ "string 3", 123, 1000.2, null ] } } }
j←⎕JSON JSON j #.[JSON object] j.⎕NL 9 a j.a.⎕NL 2 b c j.a.b ┌────────┬────────┐ │string 1│string 2│ └────────┴────────┘ j.a.c ┌────┐ │true│ └────┘ j.a.⎕NL 9 d j.a.d.⎕NL 2 ⍝ Note that f⍺ is an invalid APL name e ⍙f⍙9082⍙ j.a.d.e ┌─────┐ │false│ └─────┘ j.a.d.⍙f⍙9082⍙ ┌────────┬───┬──────┬──────┐ │string 3│123│1000.2│┌────┐│ │ │ │ ││null││ │ │ │ │└────┘│ └────────┴───┴──────┴──────┘
(⎕JSON⍠'M')JSON ┌─┬──┬────────┬─┐ │0│ │ │1│ ├─┼──┼────────┼─┤ │1│a │ │1│ ├─┼──┼────────┼─┤ │2│b │ │2│ ├─┼──┼────────┼─┤ │3│ │string 1│4│ ├─┼──┼────────┼─┤ │3│ │string 2│4│ ├─┼──┼────────┼─┤ │2│c │┌────┐ │6│ │ │ ││true│ │ │ │ │ │└────┘ │ │ ├─┼──┼────────┼─┤ │2│d │ │1│ ├─┼──┼────────┼─┤ │3│e │┌─────┐ │6│ │ │ ││false│ │ │ │ │ │└─────┘ │ │ ├─┼──┼────────┼─┤ │3│f⍺│ │2│ ├─┼──┼────────┼─┤ │4│ │string 3│4│ ├─┼──┼────────┼─┤ │4│ │123 │3│ ├─┼──┼────────┼─┤ │4│ │1000.2 │3│ ├─┼──┼────────┼─┤ │4│ │┌────┐ │5│ │ │ ││null│ │ │ │ │ │└────┘ │ │ └─┴──┴────────┴─┘
Y is the data to be exported as JSON and may be an array, a namespace or a matrix representation of JSON such as would have been produced by JSON Import with Format 'M'. Y is interpreted according to the Format variant which may be 'D'(the default) or 'M'.
⎕JSON will signal DOMAIN ERROR if Y is incompatible with the specified (or implied) value of Format.
If Format is M, the data values in Y[;3] must correspond precisely with the JSON types specified in Y[;4]as specified in the following table.
Y[;4] (Type) | Y[;3] (Value) |
---|---|
1 | Empty array |
2 | Empty array |
3 | Numeric scalar |
4 | Character vector |
5 | Null |
6 | Enclosed character vector |
7 | Enclose character vector |
R is a character vector whose content depends upon the value of the Compact variant.
If Compact is 0, the JSON text is padded with spaces and new lines for readability.
If Compact is 1 (the default) the JSON text is compacted into its minimal form.
The name of any namespace member that begins with ⍙ and otherwise conforms to the conversion format used for JSON object names will be demangled.
j ⍝ See above #.[JSON object] ⍴JS←1 ⎕JSON j 94 JS {"a":{"b":["string 1","string 2"],"c":true,"d":{"e":false,"f⍺":["string 3",123,1000.2,null]}}} 1(⎕JSON⍠'Compact' 0) j { "a": { "b": [ "string 1", "string 2" ], "c": true, "d": { "e": false, "f⍺": [ "string 3", 123, 1000.2, null ] } } }
If there are any mis-matches between the values in Y[;3] and the types in Y[;4], ⎕JSON will signal DOMAIN ERROR and report the first row where there is a mis-match (⎕IO sensitive) as illustrated in the following example.
M←(⎕JSON⍠'Format' 'M')'{"values": [ 75, 300 ]}' M ┌─┬──────┬───┬─┐ │0│ │ │1│ ├─┼──────┼───┼─┤ │1│values│ │2│ ├─┼──────┼───┼─┤ │2│ │75 │3│ ├─┼──────┼───┼─┤ │2│ │300│3│ └─┴──────┴───┴─┘
M[3;3]←⊂'75' ⍝ character not numeric M ⍝ but looks the same as before ┌─┬──────┬───┬─┐ │0│ │ │1│ ├─┼──────┼───┼─┤ │1│values│ │2│ ├─┼──────┼───┼─┤ │2│ │75 │3│ ├─┼──────┼───┼─┤ │2│ │300│3│ └─┴──────┴───┴─┘
1 (⎕JSON⍠ 'Format' 'M')M DOMAIN ERROR: Value does not match the specified type in row 3 1(⎕JSON⍠'Format' 'M')M ∧
The following example illustrates how JavaScript objects may be exported.
In the example, the object is a JavaScript function which is specified by the contents of an enclosed character vector. Note that in this case Dyalog performs no validation of the code itself.
'Slider' ⎕NS '' Slider.range←⊂'true' ⍝ Note the ⊂ Slider.min←0 Slider.max←500 Slider.values←75 300 fn1←' function( event, ui ) {' fn2←'$( "#amount" ).val( "$" + ui.values[ 0 ] +' fn2,←' " - $" + ui.values[ 1 ] );}' Slider.slide←,/fn1 fn2 ⍝ Enclosed character vec
⍴JS←1 ⎕JSON Slider 159 JS {"max":500,"min":0,"range":true,"slide": function( event, ui ) {$( \"#amount\" ).val( \"$\" + ui.values[ 0 ] + \" - $\" + ui.values[ 1 ] );},"values":[75,300]}
The JSON standard describes a limited set of data types and JSON does not provide a general APL import/export mechanism. In particular:
For example, arrays with more than one dimension cannot be represented in JSON. Of course, this does mean that applications using JSON are unlikely to use such objects; you probably will need rearrange your data into the format that is expected by the receiving application. In the case of a 2-dimensional matrix, a split will give you a vector of tuples that a JSON application is likely to expect:
⎕JSON 3 4⍴⍳12 DOMAIN ERROR: Array unsupported by JSON ⎕JSON 3 4⍴⍳12 ∧ ⎕JSON ↓3 4⍴⍳12 [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
The JSON standard includes Boolean values true and false which are distinct from numeric values 1 and 0, and have no direct APL equivalent.
To represent JSON true and false types this implementation adopts the convention of using APL arrays ⊂'true' and ⊂'false' respectively. These arrays cannot otherwise be represented in JSON and allow true and false to be uniquely identified.
The names of JSON object members which would not be valid for APL are modified. See JSON Name Mangling.
When Dyalog converts from JSON to APL data, and a member of a JSON object has a name which is not a valid APL name, it is renamed.
In this example, the JSON describes an object containing two numeric items, one named a (which is a valid APL name) and the other named 2a (which is not):
{"a": 1, "2a": 2}
When this JSON is imported as an APL namespace using ⎕JSON, Dyalog converts the name 2a to a valid APL name. The name mangling algorithm creates a name beginning with ⍙.
(⎕JSON'{"a": 1, "2a": 2}').⎕NL 2 a ⍙2a
When Dyalog exports JSON it performs the reverse name mangling, so:
1 ⎕JSON ⎕JSON'{"a": 1, "2a": 2}' {"a":1,"2a":2}
Should you need to create and decode these names directly,7162⌶ provides the same name mangling and un-mangling operations. See JSON Translate Name.
0(7162⌶)'2a' ⍙2a 1(7162⌶)'⍙2a' 2a